package com.speedtickets.rest.controller;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.codehaus.jettison.json.JSONException;

import com.speedtickets.rest.beans.TicketBean;
import com.speedtickets.rest.beans.VehicleBean;
import com.speedtickets.rest.exceptions.ForbiddenKeyException;
import com.speedtickets.rest.exceptions.InvalidKeyException;
import com.speedtickets.rest.exceptions.ValidationException;
import com.speedtickets.rest.models.Ticket;
import com.speedtickets.rest.models.Vehicle;
import com.speedtickets.rest.services.ITicketService;
import com.speedtickets.rest.services.IVehicleService;
import com.speedtickets.rest.services.factory.TicketServiceFactory;
import com.speedtickets.rest.services.factory.VehicleServiceFactory;
import com.speedtickets.rest.utils.AuthorizationUtils;
import com.speedtickets.rest.utils.HandleEvents;
import com.speedtickets.rest.utils.ParseUtils;
import com.speedtickets.rest.validators.Validator;

@Path("/vehicles")
public class VehicleController {

	private static IVehicleService _vehicleService = VehicleServiceFactory.getInstance().getVehicleServices();
	
	private static ITicketService _ticketService = TicketServiceFactory.getInstance().getTicketServices();
	
	private Validator _validator = new Validator();
	
	private AuthorizationUtils _authorize = new AuthorizationUtils();
	
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response postVehicle( VehicleBean vehicleBean, @QueryParam("apiKey") String apiKey ) throws JSONException, IllegalArgumentException, IllegalAccessException{
		
		try {
			_authorize.retrictKeys(apiKey);
			_validator.validate(vehicleBean);
			
			Vehicle vehicle = ParseUtils.parse(vehicleBean);
			_vehicleService.createVehicle(vehicle);
			
			return Response.status(201).entity(HandleEvents.handleSucess(vehicle.getId(), "vehicles", "POST", 201)).build();
		} catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch (ForbiddenKeyException fke){
			return Response.status(403).entity(HandleEvents.handleForbidden(403)).build();
		} catch (ValidationException ve){
			return Response.status(400).entity(HandleEvents.handleBadRequest(ve.getMessage(), 400)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
		
	}
	
	@PUT
	@Path("/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public Response putVehicle(@PathParam("id") String id, VehicleBean vehicleBean, @QueryParam("apiKey") String apiKey) throws JSONException, IllegalArgumentException, IllegalAccessException, ValidationException{
		
		try {
			_authorize.retrictKeys(apiKey);
			Vehicle vehicleDB = _vehicleService.findVehicleById(Long.parseLong(id));
			if(vehicleDB == null){
				return Response.status(404).entity(HandleEvents.handleNotFoundError(id)).build();
			}
			Vehicle vehicleUpdate = ParseUtils.parse(vehicleBean);
			if(vehicleDB != null){
				vehicleUpdate.setId(vehicleDB.getId());
			}
			_validator.validate(vehicleBean);
			_vehicleService.updateVehicle(vehicleUpdate);
			return Response.status(200).entity(HandleEvents.handleSucess(vehicleUpdate.getId(), "vehicles", "PUT", 200)).build();
		} catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch (ForbiddenKeyException fke){
			return Response.status(403).entity(HandleEvents.handleForbidden(403)).build();
		} catch (ValidationException ve){
			return Response.status(400).entity(HandleEvents.handleBadRequest(ve.getMessage(), 400)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
	}

	
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVehicles(@QueryParam("apiKey") String apiKey, @QueryParam("limit") Integer limit, @QueryParam("offset") Integer offset ) throws JSONException{
		
		try {
			_authorize.noRestriction(apiKey);
			List<Vehicle>vehiclesList = new ArrayList<Vehicle>();
			//Verifica se os parametros limit e offset estão sendo 
			//passados na query, se estiverem utiliza mecanismo de 
			//paginação, senão retorna os resultados por completo
			if(limit != null && offset != null){
				vehiclesList = _vehicleService.findAllVehicles(limit, offset);
			} else {
				vehiclesList = _vehicleService.findAllVehicles();
			}
			List<VehicleBean> beanList = new ArrayList<VehicleBean>();
			for (Vehicle vehicle : vehiclesList) {
				VehicleBean bean = ParseUtils.parse(vehicle);
				beanList.add(bean);
			}
			return Response.status(200).entity(beanList).build();
		}
		catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
		
	}
	
	@GET
	@Path("/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVehicle(@PathParam("id") String id, @QueryParam("apiKey") String apiKey) throws JSONException{
		try{
			_authorize.noRestriction(apiKey);
			Vehicle vehicle = _vehicleService.findVehicleById(Long.parseLong(id));
			if(vehicle == null){
				return Response.status(404).entity(HandleEvents.handleNotFoundError(id)).build();
			}
			VehicleBean bean = ParseUtils.parse(vehicle);
			return Response.status(200).entity(bean).build();
		} catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
	}
	
	@GET
	@Path("/{id}/tickets")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVehicleTickets(@PathParam("id") String id, @QueryParam("apiKey") String apiKey) throws JSONException{
		try{
			_authorize.noRestriction(apiKey);
			Vehicle vehicle = _vehicleService.findVehicleById(Long.parseLong(id));
			if(vehicle == null){
				return Response.status(404).entity(HandleEvents.handleNotFoundError(id)).build();
			}
			
			List<TicketBean>vehicleTickets = new ArrayList<TicketBean>();
			for(Long ticketId: vehicle.getTicketIds()){
				Ticket ticket = _ticketService.findTicketById(ticketId);
				TicketBean bean = ParseUtils.parse(ticket);
				vehicleTickets.add(bean);
			}
			return Response.status(200).entity(vehicleTickets).build();
		} catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
	}
	
	@DELETE
	@Path("/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public Response deleteVehicles(@PathParam("id") String id, @QueryParam("apiKey") String apiKey) throws JSONException{
		try {	
			_authorize.retrictKeys(apiKey);
			Vehicle vehicleDB = _vehicleService.findVehicleById(Long.parseLong(id));
			if(vehicleDB == null){
				return Response.status(404).entity(HandleEvents.handleNotFoundError(id)).build();
			}
			_vehicleService.deleteVehicle(vehicleDB);
			return Response.status(200).entity(HandleEvents.handleSucess(vehicleDB.getId(), "vehicles", "DELETE", 200)).build();
		} catch (InvalidKeyException ike){
			return Response.status(401).entity(HandleEvents.handleUnauthorized(401)).build();
		} catch (ForbiddenKeyException fke){
			return Response.status(403).entity(HandleEvents.handleForbidden(403)).build();
		} catch(Exception e){
			return Response.status(500).entity(HandleEvents.handleServerError(500)).build();
		}
	}
}
